package com.trc202.CS350;
//Term Project Ted Chandler and Daniel Moore
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Random;

import com.trc202.MemoryManagers.FCFSBestFit;
import com.trc202.MemoryManagers.FCFSFirstFit;
import com.trc202.MemoryManagers.MemoryManager;
import com.trc202.MemoryManagers.SJFirstServed;

public class Main {

	private int numProcessors = 0;
	
	public Main(int processors){
		this.numProcessors = processors;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Job[] jobs = generateJobs(20, 24, 100, 4, 15);
		Job[] jobsCopy = copyJobs(jobs);
		Job[] jobsCopy1 = copyJobs(jobs);
		int memRange[] = {64, 96, 48, 32, 128, 96, 48};
		Main m = new Main(2);
		m.startMain(jobs, new FCFSFirstFit(jobs,generateSegments(memRange)), "FCFSFirstFit.txt");
		m.startMain(jobsCopy, new FCFSBestFit(jobsCopy, generateSegments(memRange)), "FCFSBestFit.txt");
		m.startMain(jobsCopy1, new SJFirstServed(jobsCopy1, generateSegments(memRange)), "SJFirstServed.txt");
		

	}
	
	/**
	 * Starts processing using the provided MemoryManager
	 * @param jobs
	 * @param memManager
	 * @param fileName
	 */
	public void startMain(Job[] jobs, MemoryManager memManager, String fileName){
		try {
			Writer output = new BufferedWriter(new FileWriter(fileName));
			Processor[] processors = new Processor[numProcessors];
			for(int i = 0; i < processors.length; i++){
				processors[i] = new Processor(jobs,memManager);
			}
			for(int x = 0; x < 30; x++){
				for(Processor p : processors){
					p.process();
				}
				print(jobs, memManager.getTotalWastedMemory(), x, output);
			}
			int totalJobsCompleted = 0;
			for(Job j : jobs){
				if(j.getStatus() == Job.Status.FINISHED){
					totalJobsCompleted = 1 + totalJobsCompleted;
				}
			}
			output.write("Total Jobs Completed: " + totalJobsCompleted);
			output.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Generates a set of jobs
	 * @param numJobs to be created
	 * @param ramMin Minimum amount of ram to be used
	 * @param ramMax Maximum amount of ram to be used
	 * @param timeMin Minimum time a job can require
	 * @param timeMax Maximum time a job can require
	 * @return
	 */
	public static Job[] generateJobs(int numJobs, int ramMin, int ramMax, int timeMin, int timeMax){
		if(ramMin > ramMax || ramMin < 0 || timeMin > timeMax || timeMin < 0){
			throw new RuntimeException("Invalid Selection on generate Jobs");
		}
		Random ran = new Random(System.currentTimeMillis());
		Job[] jobs = new Job[numJobs];
		for(int x = 0; x < numJobs; x++){
			int jobRam = (ran.nextInt(ramMax - ramMin + 1) + ramMin);
			int jobTime = (ran.nextInt(timeMax - timeMin + 1) + timeMin);
			Job j = new Job(x, jobTime, jobRam);
			jobs[x] = j;
		}
		return jobs;
	}

	
	/**
	 * generates a Array of memory segments as given by the input range
	 * @param range
	 * @return
	 */
	public static MemorySegment[] generateSegments(int range[]){
		MemorySegment[] segments = new MemorySegment[range.length];
		for(int x = 0; x < range.length; x++){
			segments[x] = new MemorySegment(x,range[x]);
		}
		return segments;
	}
	
	/**
	 * Returns and identical copy of the given jobs
	 * @param jobs
	 * @return
	 */
	public static Job[] copyJobs(Job[] jobs){
		Job[] jobsCopy = new Job[jobs.length];
		for(int i = 0; i < jobs.length; i++){
			jobsCopy[i] = new Job(jobs[i].getJobId(), jobs[i].getTotalExecutionTime(), jobs[i].getRequiredRam());
		}
		return jobsCopy;
	}
	
	/**
	 * Outputs the current turn to the provided Writer
	 * @param jobs
	 * @param memoryWasted
	 * @param time
	 * @param output
	 * @throws IOException
	 */
	public void print(Job[] jobs, int memoryWasted, int time, Writer output) throws IOException{
		output.write(String.format("%1$1s %2$3s %3$3s %4$8s %5$12s %6$7s %n", "Time", "ID", "Segment", "Mem_Request", "Time_Remain", "Status"));
		int jobsWaiting = 0;
		for(Job j : jobs){
			output.write(String.format("%1$1s %2$5s %3$3s %4$8s %5$12s %6$15s %n",time, j.getJobId(), j.getAssignedSegmentNum(),j.getRequiredRam(), j.getRemainingExecutionTime(), j.getStatus().toString()));
			if(j.getStatus() == Job.Status.WAITING){
				jobsWaiting = jobsWaiting + 1;
			}
		}
		output.write("Jobs Waiting: " + jobsWaiting + System.getProperty("line.separator"));
		output.write("Memory Wasted: " + memoryWasted + System.getProperty("line.separator"));
		output.write(System.getProperty("line.separator"));
	}
}
